'''
Created on Jun 11, 2009

Generates the AST Node classes from a specification given in 
 a .yaml file

 The design of this module was inspired by astgen.py from the
 Python 2.5 code-base.

@license: License: LGPL
@copyright: (c) 2009, dogsing.cn
@author: ant-man(Bin Zhao)
'''

from string import Template
import yaml


class CSTCodeGenerator( object ):

    def __init__( self, cfg_filename='_moc_tree.yaml' ):
        """ Initialize the code generator from a configuration file.
        """
        self.cfg_filename = cfg_filename
        cfg = yaml.load( open( cfg_filename ).read() )
        self.node_cfg = [CstNodeCfg( name, cfg[name] ) for name in cfg]

    def generate( self, file=None ):
        """ Generates the code into file, an open file buffer.
        """
        src = Template( _PROLOGUE_COMMENT ).substitute( 
            cfg_filename=self.cfg_filename )

        src += _PROLOGUE_CODE
        for node_cfg in self.node_cfg:
            src += node_cfg.generate_source() + '\n'

        file.write( src )

class CstNodeCfg( object ):
    def __init__( self, name, contents ):
        self.name = name
        self.strcfg = contents["tostr"]
        params = contents["param"]
        self.all_entries = [entry for entry in params]

    def generate_source( self ):
        src = self._gen_init()
        src += '\n' + self._gen_str()
        return src

    def _gen_init( self ):
        src = "class %s(CstNode):\n" % self.name

        if self.all_entries:
            args = ', '.join( self.all_entries )
            arglist = '(self, %s, coord=None)' % args
        else:
            arglist = '(self, coord=None)'

        src += "    def __init__%s:\n" % arglist

        for name in self.all_entries + ['coord']:
            src += "        self.%s = %s\n" % ( name, name )

        return src

    def _gen_str( self ):
        src = '    def __str__(self):\n'
        src += '        return %s' % self.strcfg
        return  src



_PROLOGUE_COMMENT = \
r'''"""
 ** ATTENTION **
 This code was automatically generated from the file:
 $cfg_filename 

 Do not modify it directly. Modify the configuration file and
 run the generator again.
 ** ** *** ** **

@license: License: LGPL
@copyright: (c) 2009, dogsing.cn
@author: ant-man(Bin Zhao)
"""

'''

_PROLOGUE_CODE = r'''
import sys


class CstNode(object):
    """ Abstract base class for CST nodes.
    """
    
    def accept(self, visitor):
        """
        User Visitor pattern to issue some kind of action,
        that binding with the specified type of node
        
        visitor : instance of NodeVisistor or its subclass 
        """
        return visitor.visit(self)
        
'''

if __name__ == "__main__":
    import sys

    ast_gen = CSTCodeGenerator( '_moc_cst.yaml' )
    ast_gen.generate( open( 'mocCst.py', 'w' ) )

#    for node_cfg in ast_gen.node_cfg:
#        print "def visit_%s(self, node):" % node_cfg.name
#        print "    '''visit %s'''" % node_cfg.name
#        print

    n = [node_cfg.name for node_cfg in ast_gen.node_cfg]
    print len( n )
    print ", ".join( n )
